package cc.shacocloud.redis.study.util.codeBlock;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.StrUtil;
import org.jetbrains.annotations.NotNull;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 代码块 markdown 管理者
 */
public class CodeBlockMDManage {

    private static final Map<String, Map<String, String>> sqlCache = new ConcurrentHashMap<>();

    /**
     * 获取代码块，（会从堆栈中获取调用者的类名）
     *
     * @param id id
     * @return CodeBlock
     */
    public static String get(@NotNull String id) {
        String name = CodeBlockMDManage.class.getName();

        // 寻找调用者类
        Class<?> callerClass = null;
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        try {
            int length = stackTrace.length;
            for (int i = 0; i < length; i++) {
                StackTraceElement element = stackTrace[i];
                String className = element.getClassName();
                if (name.equals(className)) {
                    className = stackTrace[i + 1].getClassName();
                    callerClass = Class.forName(className);
                    break;
                }
            }
        } catch (ClassNotFoundException ignore) {
        }

        Objects.requireNonNull(callerClass, "执行堆栈异常...");

        return get(callerClass, id);
    }

    /**
     * 获取代码块，（会从堆栈中获取上个对象的类名和方法名作为参数）
     *
     * @return CodeBlock
     */
    public static String get() {
        String name = CodeBlockMDManage.class.getName();

        // 寻找调用者类和方法名称
        Class<?> callerClass = null;
        String method = null;

        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        try {
            int length = stackTrace.length;
            for (int i = 0; i < length; i++) {
                StackTraceElement element = stackTrace[i];
                String className = element.getClassName();
                if (name.equals(className)) {
                    StackTraceElement callerElement = stackTrace[i + 1];
                    callerClass = Class.forName(callerElement.getClassName());
                    method = callerElement.getMethodName();
                    break;
                }
            }
        } catch (ClassNotFoundException ignore) {
        }

        Objects.requireNonNull(callerClass, "执行堆栈异常...");

        return get(callerClass, method);
    }

    /**
     * 获取代码块
     *
     * @param clazz 类名
     * @param id    id
     * @return 对应的sql
     */
    public static String get(@NotNull Class<?> clazz, @NotNull String id) {
        String sql = sqlCache.computeIfAbsent(clazz.getName(), k -> {
            try {
                BufferedReader reader = getReader(clazz);
                return new ConcurrentHashMap<>(CodeBlockMDParser.parser(reader));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }).get(id);

        Objects.requireNonNull(sql, "未匹配到指定id：" + id);

        return sql;
    }

    @NotNull
    private static BufferedReader getReader(Class<?> clazz) {
        CodeBlockMD codeBlockMD = AnnotationUtil.getAnnotation(clazz, CodeBlockMD.class);

        String dirPath = codeBlockMD.mdDirPath();

        if (dirPath.startsWith("/")) {
            dirPath = dirPath.substring(1);
        } else {
            throw new IllegalArgumentException("不支持的dirPath：" + dirPath + ";(路径必须以/开头，表示在resources包下)");
        }

        dirPath = dirPath.endsWith(File.separator) ? dirPath : dirPath + File.separator;

        String mdFileName = codeBlockMD.mdFileName();
        mdFileName = StrUtil.isBlank(mdFileName) ? clazz.getSimpleName() : mdFileName;

        return ResourceUtil.getResourceObj(dirPath + mdFileName + ".md").getReader(Charset.defaultCharset());
    }
}
